/** 
 * BasicWindowTitle.java
 * @author Lex
 * 2007-9-7 ����10:23:39
 */
package lex.title.basic;

import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeListener;

import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;

import org.lex.swing.ActionBuilder;

import lex.title.MaximizeRestoreButton;
import lex.util.Utilities;

public abstract class BasicWindowTitle extends PrimalWindowTitle {
	/**
	 * Buffered Frame.state property. As state isn't bound, this is kept to
	 * determine when to avoid updating widgets.
	 */
	private int state = 0;
	// ================================
	private Action closeAction = null;
	private Action minimizeAction = null;
	private Action restoreAction = null;
	private Action maximizeAction = null;
	private Action stayOnTopAction = null;
	private WindowListener windowActiveListener = null;
	private ComponentListener windowMoveListener = null;
	private PropertyChangeListener stateChangeListener = null;

	public BasicWindowTitle(JRootPane rootPane) {
		super(rootPane);
	}

	protected abstract JButton getCloseButton();

	protected abstract MaximizeRestoreButton getMaximizeRestoreButton();

	protected abstract JButton getMinimizeButton();

	protected abstract JButton getMenuButton();

	public boolean isCloseButtonAdded() {
		return this.isComponentAdded(this.getCloseButton());
	}

	public boolean isMaximizeRestoreButtonAdded() {
		return isComponentAdded(getMaximizeRestoreButton());
	}

	public boolean isMinimizeButtonAdded() {
		return this.isComponentAdded(this.getMinimizeButton());
	}

	public boolean isMenuButtonAdded() {
		return this.isComponentAdded(this.getMenuButton());
	}

	public void addNotify() {
		super.addNotify();
		uninstallListeners();
		window = SwingUtilities.getWindowAncestor(this);
		if (window != null) {
			if (window instanceof Frame) {
				setState(((Frame) window).getExtendedState());
			} else {
				setState(0);
			}
			setActive(window.isActive());
			installListeners();
		}
	}

	public void removeNotify() {
		super.removeNotify();
		uninstallListeners();
		window = null;
	}

	protected void close() {
		if (window != null) {
			window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
		}
	}

	protected void minimize() {
		Frame frame = getFrame();
		if (frame != null) {
			frame.setExtendedState(state | Frame.ICONIFIED);
		}
	}

	protected void maximize() {
		Frame frame = getFrame();
		if (frame != null) {
			Utilities.setMaximizeBounds(frame);
			frame.setExtendedState(state | Frame.MAXIMIZED_BOTH);
		}
	}

	protected void restore() {
		Frame frame = getFrame();
		if (frame == null) {
			return;
		}
		if ((state & Frame.ICONIFIED) != 0) {
			frame.setExtendedState(state & ~Frame.ICONIFIED);
		} else {
			frame.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
		}
	}

	protected void stayOnTop(boolean onTop) {
		if (null != window) {
			window.setAlwaysOnTop(onTop);
		}
	}

	protected Action getCloseAction() {
		if (null == this.closeAction) {
			this.closeAction = new ActionBuilder("Close", 'c') {
				public void actionPerformed(ActionEvent e) {
					close();
				}
			};
		}
		return this.closeAction;
	}

	protected Action getMinimizeAction() {
		if (null == this.minimizeAction) {
			this.minimizeAction = new ActionBuilder("Minimize", 'n') {
				public void actionPerformed(ActionEvent e) {
					minimize();
				}
			};
			if (false == isFrame())
				this.minimizeAction.setEnabled(false);
		}
		return this.minimizeAction;
	}

	protected Action getMaximizeAction() {
		if (null == this.maximizeAction) {
			this.maximizeAction = new ActionBuilder("Maximize", 'x') {
				public void actionPerformed(ActionEvent e) {
					maximize();
				}
			};
			if (false == isFrame())
				this.maximizeAction.setEnabled(false);
		}
		return this.maximizeAction;
	}

	protected Action getRestoreAction() {
		if (null == this.restoreAction) {
			this.restoreAction = new ActionBuilder("Restore", 'r') {
				public void actionPerformed(ActionEvent e) {
					restore();
				}
			};
			if (false == isFrame())
				this.restoreAction.setEnabled(false);
		}
		return this.restoreAction;
	}

	protected Action getStayOnTopAction() {
		if (null == this.stayOnTopAction) {
			stayOnTopAction = new ActionBuilder("Stay On Top", 't') {
				boolean onTop = getWindow().isAlwaysOnTop();

				public void actionPerformed(ActionEvent e) {
					onTop = !onTop;
					stayOnTop(onTop);
					this.setSelected(onTop);
				}
			};
		}
		return stayOnTopAction;
	}

	/**
	 * Updates state dependant upon the Window's active state.
	 */
	protected void setActive(boolean active) {
		if (isFrame()) {
			getMinimizeAction().setEnabled(active);
			getCloseAction().setEnabled(active);
			getMaximizeAction().setEnabled(active);
			getRestoreAction().setEnabled(active);
			getStayOnTopAction().setEnabled(active);
		}
		getRootPane().repaint();
	}

	/**
	 * Sets the state of the Window.
	 */
	protected void setState(int state) {
		setState(state, false);
	}

	/**
	 * Sets the state of the window. If <code>updateRegardless</code> is true
	 * and the state has not changed, this will update anyway.
	 */
	void setState(int state, boolean updateRegardless) {
		Window w = getWindow();
		if (null == w || false == isFrame())
			return;
		if (this.state == state && false == updateRegardless)
			return;
		// =======================
		Frame frame = getFrame();
		if (frame != null) {
			if (frame.isResizable()) {
				if ((state & Frame.MAXIMIZED_BOTH) != 0) {
					getMaximizeRestoreButton().setToRestoreButton();
					getMaximizeAction().setEnabled(false);
					getRestoreAction().setEnabled(true);
				} else {
					getMaximizeRestoreButton().setToMaxButton();
					getMaximizeAction().setEnabled(true);
					getRestoreAction().setEnabled(false);
				}
			} else {
				getMaximizeAction().setEnabled(false);
				getRestoreAction().setEnabled(false);
			}
		} else {
			// Not contained in a Frame
			getMaximizeAction().setEnabled(false);
			getRestoreAction().setEnabled(false);
			getMinimizeAction().setEnabled(false);
			revalidate();
			repaint();
		}
		getCloseAction().setEnabled(true);
		this.state = state;
	}

	protected void installListeners() {
		if (window != null) {
			window.addWindowListener(getWindowActiveListener());
			window.addPropertyChangeListener(getStateChangeListener());
			window.addComponentListener(getWindowMoveListener());
		}
	}

	protected void uninstallListeners() {
		if (window != null) {
			window.removeWindowListener(getWindowActiveListener());
			window.removePropertyChangeListener(getStateChangeListener());
			window.removeComponentListener(this.getWindowMoveListener());
		}
	}

	private WindowListener getWindowActiveListener() {
		if (null == this.windowActiveListener) {
			this.windowActiveListener = new WindowActiveListener(this);
		}
		return this.windowActiveListener;
	}

	private ComponentListener getWindowMoveListener() {
		if (null == this.windowMoveListener) {
			this.windowMoveListener = new WindowMoveListener(this);
		}
		return this.windowMoveListener;
	}

	private PropertyChangeListener getStateChangeListener() {
		if (null == this.stateChangeListener) {
			this.stateChangeListener = new WindowStateChangeHandler(this);
		}
		return this.stateChangeListener;
	}
}
